/**
 * @fileoverview This file contains the odfModule object. This object implements the nsIModule interface. Every XPCOM
 *               component has to supply this interface if it wants to be registered by the system. It is the main entry
 *               point by which the system accesses an XPCOM component. The nsIModule Interface has to supply 4 methods:
 *               getClassObject, registerSelf, unregisterSelf, canUnload
 *
 * Some of the codes used were based on the following existing addons for Firefox.
 * 1. ODFReader 0.2.1 (Updated October 24, 2006)
 *     https://addons.mozilla.org/en-US/firefox/addon/1888
 *    @author Talin(C) 2005-6
 *    @author Alex Hudson (C) 2006
 *    Released under the MPL/LGPL/GPL tri-license
 * 2. OdfPlugin 0.17b (Updated October 23, 2007)
 *     https://addons.mozilla.org/en-US/firefox/addon/5907
 *    @author David Staessens (02-05-07)
 * - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - = - =
 *
 * @author last modified by: Jamie L. Vargas (2009/08/03)
 * Released under GPLv3. See file gpl-3.0.txt included in this package.
 */

/* Module Object: This object implements the nsIModule interface. */
var odfModule = new Object();

/**
 * When the nsIModule is discovered, this method will be called so that any setup registration can be performed.
 *
 * @param {nsIComponentManager} aCompMgr The global component manager.
 * @param {nsIFile} aLocation The location of the nsIModule on disk (Automatically supplied).
 * @param {string} aLoaderStr Opaque loader specific string (Automatically supplied).
 * @param {string} aType Loader Type being used to load this module (Automatically supplied).
 * @return {void}
 */
odfModule.registerSelf = function(aCompMgr, aLocation, aLoaderStr, aType) {
    logDebug("odfModule::registerSelf", "nsIModule discovered, performing registration setup.");

    var aCompMgr = aCompMgr.QueryInterface(Ci.nsIComponentRegistrar);
    var categoryManager = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager);

    // Add all the ODF MIME-types to the category manager.
    for ( var i in ODF_TYPES) {
        var mtype = ODF_TYPES[i][0];
        var fext = ODF_TYPES[i][1];
        var conversion = '?from=' + mtype + '&to=*/*';

        /*
         * The addCategoryEntry function sets the value for the given entry on the given category. The category and/or
         * entry are created if they do not exist.
         *
         * string addCategoryEntry( in string aCategory, in string aEntry, in string aValue, in boolean aPersist, in
         * boolean aReplace );
         */
        categoryManager.addCategoryEntry("ext-to-type-mapping", fext, mtype, true, true); // FIXED: persist flag should be true
        logDebug("odfModule::registerSelf", "Registered " + fext + " mimetype to this plugin.");

        /*
         * Adds an entry that will will map our ContractID to the right name. Needed if we want it to be accessible
         * through the Components.classes[] object.
         */
        categoryManager.addCategoryEntry("@mozilla.org/streamconv;1", conversion, fext + " to HTML stream converter",
            true, true);
        logDebug("odfModule::registerSelf", "Registered the ContractID for conversion " + conversion);

        /*
         * Registers a factory to be used to instantiate a particular class identified by ClassID, and creates an
         * association of class name and ContractID with the class.
         *
         * void registerFactoryLocation(in nsCIDRef aClassID, in string aClassName, in string aContractID, in nsIFile
         * aFile, in string aLoaderStr, in string aType);
         */
        aCompMgr.registerFactoryLocation(ODFPLUGIN_CID, "ODF Stream Converter",
            "@mozilla.org/streamconv;1" + conversion, aLocation, aLoaderStr, aType);
        logDebug("odfModule::registerSelf", "Registered factory location for " + mtype);
    }

    logDebug("odfModule::registerSelf", "Registering done.");
}

/**
 * When the nsIModule is being unregistered, this method will be called so that any cleanup can be performed.
 *
 * @param {nsIComponentManager} aCompMgr The global component manager.
 * @param {nsIFile} aLocation The location of the nsIModule on disk (Automatically supplied).
 * @param {string} aLoaderStr Opaque loader specific string (Automatically supplied).
 * @return {void}
 */
odfModule.unregisterSelf = function(aCompMgr, aLocation, aLoaderStr) {
    logDebug("odfModule::unregisterSelf", "Performing unregistration.");
    // remove preferences
    var prefService = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService);
    var branch = prefService.getBranch("extensions.odfview.");
    branch.deleteBranch("");
}

/**
 * This method returns a class object for a given ClassID and IID. The system will use this method to go from the
 * interface object to the class object. This method is typically used to access a nsIFactory or nsIClassInfo instance
 * for a class implemented by this component.
 *
 * @param {nsIComponentManager} aCompMgr The global component manager.
 * @param {nsCIDRef} aClass The ClassID of the object instance requested.
 * @param {nsIIDRef} aIID The IID of the object instance requested.
 * @return odfStreamConverterFactory - [iid_is(aIID),retval] {nsQIResult} aResult The resulting interface pointer.
 *
 * @throws NS_ERROR_FACTORY_NOT_REGISTERED Indicates that the requested class is not available. e.g. If our nsIModule
 *             isn't attached to a class with ClassID
 * @throws NS_ERROR_NO_INTERFACE Indicates that the requested interface is not supported. e.g. it's not called with an
 *             nsIfactory interface with IID
 */
odfModule.getClassObject = function(aCompMgr, aClass, aIID) {
    logDebug("odfModule::getClassObject",
            "Trying to access the class object with specified ClassID " + aClass + " and IID " + aIID);

    if ((aClass.equals(ODFPLUGIN_CID)) && (aIID.equals(Ci.nsIFactory))) {
        if (!oSCFLoaded) {
            throw Components.results.NS_ERROR_FACTORY_NOT_LOADED;
        } else {
            return odfStreamConverterFactory;
        }
    }

    if (!aIID.equals(Ci.nsIFactory)) {
        throw Components.results.NS_ERROR_NO_INTERFACE;
    }

    throw Components.results.NS_ERROR_FACTORY_NOT_REGISTERED; //NS_ERROR_NOT_IMPLEMENTED;
}

/**
 * This method may be queried to determine whether or not the component module can be unloaded by XPCOM. If the
 * component module is native (i.e., as part of a DLL), then this method may be called to determine whether or not the
 * DLL may be unloaded from memory. (Note that as of Mozilla 1.7, native component modules are never unloaded.)
 *
 * @param {nsIComponentManager} aCompMgr The global component manager.
 * @return {boolean} The return value of this method indicates to the caller whether or not the component module can be
 *         unloaded. <br>
 *         Returning true isn't a guarantee that the module will be unloaded. It constitutes only willingness of the
 *         module to be unloaded. It is very important to ensure that no outstanding references to the module's
 *         code/data exist before returning true. <br>
 *         Returning false guarantees that the module will not be unloaded.
 */
odfModule.canUnload = function(aCompMgr) {
    logDebug("odfModule::canUnload", "Checking if the module can be unloaded.");
    return true;
}

var nsIModLoaded = true;
